package com.knowswift.security.filter;

import com.knowswift.common.common.Assert;
import com.knowswift.common.utils.JSONUtils;
import com.knowswift.security.token.AppleAuthenticationToken;
import lombok.SneakyThrows;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;

/**
 * @Date 2021/4/15
 **/


public class AppleAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private final Class<? extends AppleAuthenticationToken> auth;

    public AppleAuthenticationFilter(String loginPattern, Class<? extends AppleAuthenticationToken> auth) {
        super(new AntPathRequestMatcher(loginPattern, "POST"));
        setSessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
        this.auth = auth;
    }

    public AppleAuthenticationFilter(String loginPattern, Class<? extends AppleAuthenticationToken> auth,
                                     AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
        super(new AntPathRequestMatcher(loginPattern, "POST"));
        setSessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
        this.auth = auth;
        this.setAuthenticationSuccessHandler(successHandler);
        this.setAuthenticationFailureHandler(failureHandler);
    }

    @Override
    public void afterPropertiesSet() {
        Assert.notNull(getSuccessHandler(), "AuthenticationSuccessHandler must be specified");
        Assert.notNull(getFailureHandler(), "AuthenticationFailureHandler must be specified");
        Assert.notNull(getAuthenticationManager(), "authenticationManager must be specified");
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse httpServletResponse) throws AuthenticationException {
        Authentication result;
        String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
        String appleId = null;
        if (StringUtils.hasText(body)) {
            LinkedHashMap<?, ?> object = JSONUtils.parseObject(body);
            appleId = (String) object.get("appleId");
        }
        if (!StringUtils.hasText(appleId)) {
            throw new BadCredentialsException("Apple ID不可为空");
        }

        AppleAuthenticationToken authRequest = auth.getConstructor(String.class).newInstance(appleId);
        result = this.getAuthenticationManager().authenticate(authRequest);
        return result;
    }
}
